package uk.co.hephistocles.blobGame;

import java.util.Vector;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.math.Vector2;

public class Player {
	private Level parent;
    private Vector2 weight = new Vector2();
    public double weightAngle = Math.PI/2;
    private double startAngle = 0;
    private Vector2 collisionForces = new Vector2();
    private Vector2 colResolution = new Vector2();
    private Vector2 vel = new Vector2();
    private float rotVel = 0;
    private Vector2 accel = new Vector2();
    public Vector2 pos = new Vector2();
    private double mass = 0.1;
    private double e = 0.1;
    private Character face;
    private Character highlight;
    private Character body;
    private int spriteState;
    private final int faceNORM = 0;
    private final int faceSQUISH = 1;
    private final int faceDEAD = 2;
    private final int faceHAPPY = 3;
    
    
	private int fps;
	public static final int width = 60;
	public static final int height = 60;
	public static final float circumference = (float) (width*Math.PI);
	public static final int radius = 27;
	
	
    
    public Player(int x, int y, int fps, Level dad) {
    	parent = dad;
    	
    	this.fps = fps;
    	//set initial gravity
    	weight.set(0, 0);
    	//set position in the center of the screen
    	pos.set(x, y);
    	//set initially at rest
    	vel.set(0, 0);
    	//F = ma => a = F/m
    	accel = weight.tmp().mul((float) (1.0/mass));
    	//during a collision, reaction force has an effect
    	accel.add(collisionForces.tmp().mul((float) (1.0/mass)));
        //lastTime is used to see how long since last frame

	    //sprite contains the graphic for the player
		face = new Character(1,60,60,1,Gdx.files.internal("res/blob/faceNorm.png"));
		highlight = new Character(1,60,60,1,Gdx.files.internal("res/blob/highlight.png"));
		body = new Character(1,60,60,1,Gdx.files.internal("res/blob/body.png"));
		spriteState=faceNORM;
		face.setOrigin(30,30);
		highlight.setOrigin(30,30);
		body.setOrigin(30,30);
		
    }
    public void reset() {
    	
    	this.fps = fps;
    	//set initial gravity
    	weight.set(0, 0);
    	//set initially at rest
    	vel.set(0, 0);
    	
    }
    public void setRotation(float a) {
    	face.setRotation(a);
    	body.setRotation(a);
    }
    
    
    
    public void update(Vector<Double> normals, Vector<Boolean> isCollided, int wallState) {
    	float setAngle = (float) weightAngle;
		if (Game.touchControl){
			if (Gdx.input.isTouched()) {
				if (startAngle == 0) {
					startAngle = Math.atan2(Gdx.input.getX() -Gdx.graphics.getWidth()/2,
							Gdx.graphics.getHeight()/2 - Gdx.input.getY());
				} else {
					setAngle -= (Math.atan2(Gdx.input.getX() -Gdx.graphics.getWidth()/2,
							Gdx.graphics.getHeight()/2 - Gdx.input.getY())- startAngle);
					startAngle =  Math.atan2(Gdx.input.getX() -Gdx.graphics.getWidth()/2,
							Gdx.graphics.getHeight()/2 - Gdx.input.getY());
				}
				
			}else {
				startAngle = 0;
			} 

		}
		if (Game.keyBoardControl) {
			if (Gdx.input.isKeyPressed(21)) {
				setAngle+=0.1;
			} else if (Gdx.input.isKeyPressed(22)) {
				setAngle-=0.1;
			}
		}
		if ((!Game.keyBoardControl)&&(!Game.keyBoardControl)) {
			setAngle = (float) Math.atan2(Gdx.input.getAccelerometerX(), Gdx.input.getAccelerometerY());
		}
		update (normals, isCollided, wallState, setAngle);
    }
    
    public void update(Vector<Double> normals, Vector<Boolean> isCollided, int wallState, float setAngle) {
			weightAngle = setAngle;
			weight.set((float) (100*Math.cos(weightAngle)),(float) (-100*Math.sin(weightAngle)));
			parent.rotateChildren(weight.angle()+90);

	    	collisionForces.set(0, 0);
	    	int i;
	    	Vector2 collidedNormal = new Vector2();
	    	for (i=0; i<isCollided.size(); i++) {
	    		if (isCollided.get(i)) {
		    		collide(normals.get(i));
		    		collidedNormal = new Vector2((float) (Math.cos(normals.get(i))),
		    				(float) (Math.sin(normals.get(i))));
	    		}
	    	}
			//F=ma again
	    	
	    	accel = weight.cpy().mul((float) (1.0/mass));
	    	accel.add(collisionForces.tmp().mul((float) (1.0/mass)));

	    	//v=u+at
	    	vel.add(accel.tmp().mul((float) (1.0/fps)));
	    	if (collidedNormal.len2() !=0) {
		    	rotVel = collidedNormal.crs(vel)/50;
		    	if (Math.abs(rotVel) > 15) {
		    		if (spriteState!= faceSQUISH) {
		    			spriteState = faceSQUISH;
		    			face.setStats(1,60,60,1,Gdx.files.internal("res/blob/faceSquish.png"));
		    		}
		    	}else {
		    		//if in the air
		    		if (wallState<-1) {
			    		if (spriteState != faceHAPPY) {
			    			face.setStats(1,60,60,1,Gdx.files.internal("res/blob/faceHappy.png"));
			    			spriteState = faceHAPPY;
			    		}
		    		//if on the wall
			    	} else if (wallState>1) {
			    		if (spriteState != faceNORM) {
			    			face.setStats(1,60,60,1,Gdx.files.internal("res/blob/faceNorm.png"));
			    			spriteState = faceNORM;
			    		}
			    	}
	    		}
	    	} else {
	    		rotVel *= 0.99;
	    	}
	    	/*if (wallState==1) {
	    		body.setRotation(collidedNormal.angle()-90);
	    		body.setStats(10, 60, 60, 4, Gdx.files.internal("res/blob/bodySquish.png"));
	    	} else if (body.completed) {
    			body.setStats(1,60,60,1,Gdx.files.internal("res/blob/body.png"));
	    	}*/

	    	//s=x+vt
	    	//TODO:
	    	pos.add(vel.tmp().mul((float) (1.0/fps)));
	    	//l("final pos: " + pos);
	    	face.rotate(rotVel);
	    	highlight.rotate(rotVel);
			body.rotate(rotVel);
			
			face.update();
			highlight.update();
			body.update();
    }
    public void die() {
		face.setStats(1,60,60,1,Gdx.files.internal("res/blob/faceDead.png"));
    	draw();
    }
    public void draw() {
		body.draw((int)pos.x,(int)pos.y);
    	highlight.draw((int)pos.x,(int)pos.y);
    	face.draw((int)pos.x,(int)pos.y);
    }
    //normal is angle from surface to player
    private void collide(double normal) {
    	//normal = direction of the resolving force
    	//Create a vector in the direction of the bounce
    	colResolution.set((float)Math.cos(normal), (float)Math.sin(normal));
    	//get the perpendicular component of weight
    	double perpComponent = weight.dot(colResolution);
    	if (perpComponent < 0){
	    	//apply an equal and opposite force to keep the object from entering surface
    		//create a vector in the direction of bounce, scale to projection of weight
	    	collisionForces.add(colResolution.tmp().nor().mul((float) -weight.dot(colResolution)));
	    	}
    	if (vel.dot(colResolution) < 0){
    		//collision must occur, so negate perpendicular component of vel
    		//Speed of separation = e*speed of approach
    		//create new vector in direction of bounce
    		Vector2 v = colResolution.tmp().nor();
    		v.mul((float) (-vel.dot(colResolution)*(1+e)));
    		vel.add(v);
    	}
	
    }
}
